#ifndef CV_FACE_DETECTOR_H
#define CV_FACE_DETECTOR_H

#include "McRaster.h"
//#include "ItgImage.h"

#define CV_HAAR_FEATURE_MAX  3
typedef unsigned int ulong;
typedef unsigned int sumtype;
typedef float sqsumtype;

class CvRectangle
{
public:
	CvRectangle()
	{
		x		= 0;
		y		= 0;
		width	= 0;
		height	= 0;
	};
	
	CvRectangle(const int x1, const int y1, const int width1, const int height1)
	{
		x		= x1;
		y		= y1;
		width	= width1;
		height	= height1;
	};
	
	bool operator==(const CvRectangle &a)
	{
		return width==a.width && height==a.height && x==a.x && y==a.y;
	}

public:
	int width;
	int height;
	int x;
	int y;
};

class CvRectWeight
{
public:
	bool operator==(const CvRectWeight &a)
	{
		return (r==a.r && weight==a.weight);
	}

public:
	CvRectangle	r;
	float	weight;
};

#define calc_sum(rect,offset) \
    ((rect).p0[offset] - (rect).p1[offset] - (rect).p2[offset] + (rect).p3[offset])

/////////////////////////////////////////////
/////////////////////////////////////////////
class CvHaarFeature
{
public:

	bool operator==(const CvHaarFeature&a)
	{
		bool bsame=true;

		bsame = (tilted==a.tilted);
		for (int i=0; i<CV_HAAR_FEATURE_MAX; i++)
			bsame = bsame && (rect[i]==a.rect[i]);
		return bsame;
	}

public:
    int				tilted;
	CvRectWeight	rect[CV_HAAR_FEATURE_MAX];
};


/////////////////////////////////////////////
/////////////////////////////////////////////
class CvHidHaarFeature
{
public:
    struct
    {
        sumtype *p0, *p1, *p2, *p3;
        float	weight;
    }
    rect[CV_HAAR_FEATURE_MAX];
};

////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////
class CvHidHaarClassifier
{
public:
	// construction & destruction
	CvHidHaarClassifier();
	~CvHidHaarClassifier();
	void	Free(void);
	void	SetNumFeatures(const int num);
	
public:
    int					count;

	float				*p_threshold;
    int					*p_left;
    int					*p_right;
    float				*p_alpha;

    CvHaarFeature		*p_orig_feature;
    CvHidHaarFeature	*p_feature;
};

////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////
class CvHidHaarStageClassifier
{
public:
	// construction & destruction
	CvHidHaarStageClassifier();
	~CvHidHaarStageClassifier();
	void	Free(void);
	void	SetNumClassifiers(const int num);
	inline	int Classify(const int offset_p, const double variance_norm_factor);
	inline	int	ClassifyStump(const int offset_p, const double variance_norm_factor);

public:
    int		count;
    float	threshold;
    int		two_rects;

    CvHidHaarClassifier	*p_classifier;
};

inline	int CvHidHaarStageClassifier::Classify(const int offset_p, const double variance_norm_factor)
{
	CvHidHaarClassifier* classifier;
	CvHidHaarFeature* feature;
	double	sum, t,a,b,stage_sum;
	int		j;
	
	stage_sum = 0.0;
	if (two_rects)
		for (j = 0; j < count; j++)
		{
			classifier = &p_classifier[j];
			feature = classifier->p_feature;
			t = classifier->p_threshold[0]*variance_norm_factor, a, b;

			sum = calc_sum(feature->rect[0],offset_p) * feature->rect[0].weight;
			sum += calc_sum(feature->rect[1],offset_p) * feature->rect[1].weight;

			a = classifier->p_alpha[0];
			b = classifier->p_alpha[1];
			stage_sum += sum < t ? a : b;
		}
	else
		for( j = 0; j < count; j++ )
		{
			classifier = &p_classifier[j];
			feature = classifier->p_feature;
			t = classifier->p_threshold[0]*variance_norm_factor;

			sum = calc_sum(feature->rect[0],offset_p) * feature->rect[0].weight;
			sum += calc_sum(feature->rect[1],offset_p) * feature->rect[1].weight;

			if(feature->rect[2].p0 )
			sum += calc_sum(feature->rect[2],offset_p) * feature->rect[2].weight;

			stage_sum += classifier->p_alpha[sum >= t];
		}
	if( stage_sum < threshold - 0.0001 )
		return 0;
	else
		return 1;		
}

inline	int	CvHidHaarStageClassifier::ClassifyStump(const int offset_p, const double variance_norm_factor)
{
	CvHidHaarClassifier* classifier;
    double	sum, t,stage_sum = 0;
	int		idx,j;

	for(j = 0; j < count; j++ )
	{
		classifier = &p_classifier[j];

		idx = 0;
		do 
		{
			t = classifier->p_threshold[idx] * variance_norm_factor;

			sum = calc_sum(classifier->p_feature[idx].rect[0],offset_p)
                        * classifier->p_feature[idx].rect[0].weight;
			sum += calc_sum(classifier->p_feature[idx].rect[1],offset_p)
                        * classifier->p_feature[idx].rect[1].weight;

			if( classifier->p_feature[idx].rect[2].p0 )
				sum += calc_sum(classifier->p_feature[idx].rect[2],offset_p) * classifier->p_feature[idx].rect[2].weight;

			idx = ( sum < t ) ? classifier->p_left[idx] : classifier->p_right[idx];

		}
		while( idx > 0 );

		stage_sum += classifier->p_alpha[-idx];
	}

	if( stage_sum < threshold - 0.0001 )
		return 0;
	else
		return 1;
}


////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////
class CvHidHaarClassifierCascade
{
public:
	// construction & destruction
	CvHidHaarClassifierCascade();
	~CvHidHaarClassifierCascade();
	void Free(void);
	void SetNumStageCalssifiers(const int num);


	// operations
	bool		LoadFromFile(const char *str_directory);
	bool		LoadCascadeCART(const char** input_cascade, int n, irmm_Size origWindowSize);


	void		UpdateRealWindowSize(double scale);
	irmm_Size	GetHaarClassifierCascadeWindowSize(void);
	double		GetHaarClassifierCascadeWindowScale(void);

public:
    int			count;
    int			is_stump_based;
    int			has_tilted_features;
    irmm_Size	origWindowSize;
    irmm_Size	realWindowSize;
    double		scale,invWindowArea;

    sqsumtype	*pq0,*pq1,*pq2,*pq3;
    sumtype		*p0, *p1,*p2,*p3;

    CvHidHaarStageClassifier *p_stage_classifier;
};



#define CV_HAAR_DO_CANNY_PRUNING 1



#endif